#include "opDir.h"
#include "stack.h"

// cdDir专用, 得到最简路径的路径栈
static int getPathStack(LinkedStack *stack, char *p) {
    // .. 弹栈, 判空   .不处理   普通的压栈
    if(strcmp(p, "..") == 0) {
        char data[256] = {0};
        int ret = stack_pop(stack, data);
        if(ret == -1) {
            return -1;
        }
    }
    else if(strcmp(p, ".") == 0) {
        return 1;
    }
    else {
        stack_push(stack, p);
    }

    return 1;
}

// cdDir专用, 得到两个路径的不同之处
static int getPathDiff(const char *path1, const char *path2, char *diff) {
    // 找出两个路径共同的前缀长度
    int common_len = 0;
    while ((path1[common_len] != '\0') && 
           (path2[common_len] != '\0') && 
           (path1[common_len] == path2[common_len])) {
        common_len++;
    }

    // 如果完全匹配，返回0
    if ((path1[common_len] == '\0') && (path2[common_len] == '\0')) {
        return 0;
    }

    // 复制第二个路径中不同的部分到结果
    const char *diff_part = path2 + common_len + 1;
    int diff_len = strlen(diff_part);
    
    // 确保不超过结果缓冲区大小（假设result足够大）
    strncpy(diff, diff_part, diff_len);
    diff[diff_len] = '\0';

	// 1表示有不同部分
	return 1;
}

// cdDir专用, 用于将路径栈弹出, 得到最简路径, 进入此函数已代表栈非空
static void getFinFakePath(LinkedStack *stack, char *destDir) {
    char destDirTemp[1024] = {0}; 
    
    while(!stack_is_empty(stack)) {
        // 把栈顶数据取出来
        char data[1024] = {0};
        stack_pop(stack, data);
        
        // 将取出的文件夹名放入总字符串, 后取出的放前面
        char temp[1024] = {0};
        strcpy(temp, data);
        // 给每个路径文件名后加'/', 第一个(路径的最后一个)后不加
        if(destDirTemp[0] != 0) {
            strcat(temp, "/");
            strcat(temp, destDirTemp);
        }
        strcpy(destDirTemp, temp);
    }
    
    strcpy(destDir, destDirTemp);
}

int cdDir(int netfd, const char *srcDir, const char *inDir) {
    int returnValue = 1;
    // 将要打开的目录拼接成真实地址
    char destDir[1024] = {0};
    strcpy(destDir, srcDir);
    
    // 下面要考虑复杂文件路径的问题, 化成最简单的, 再拼接
    // inDir:  ../dir1/../dir2/./dir1/../dir1  --> /dir2/dir1

    // 目的：进行入栈, 化为最简进入路径
    // 先得到服务端终端路径realDir, 即源地址  e.g. realDir: /home/group
    // 再将源地址与srcDir对比, 得到多的部分        srcDir: /home/group/xjh
    // 多的部分与inDir拼接                       xjh 拼接 inDir
    // 按照入栈规则判断, 得到最终栈

    // 将最终栈依次弹出, 加到最前面, 得destDirTemp    xjh/dir2/dir1
    // 将destDtrTemp与realDir拼接, 得到最终绝对路径destDir   /home/group/xjh/dir2/dir1
    // 检查路径是否存在, 存在则发送, 不存在则失败

    char realDir[1024] = {0};
    getcwd(realDir, sizeof(realDir));
    printf("realDir is: %s\n", realDir);
    
    char diffDir[1024] = {0};
    int ret = getPathDiff(realDir, srcDir, diffDir);

    strcat(diffDir, "/");
    strcat(diffDir, inDir);
    printf("waiting for opearte path is: %s\n", diffDir);

    LinkedStack *stack = stack_create();
    char *p = strtok(diffDir, "/");
    do {
        ret = getPathStack(stack, p);
        if(ret == -1) {
            printf("cdDir无法打开更高级目录\n");
            returnValue = -1;
            break;
        }

        p = strtok(NULL, "/");
    } while(p != NULL);

    char destDirTemp[1024] = {0};
    if(returnValue == 1) {
        getFinFakePath(stack, destDirTemp);
        if(destDirTemp[0] == 0) {
            printf("getFinFakePath is NULL\n");
            returnValue =  -1;
        }
        else {
            printf("getFinFakePath is %s\n", destDirTemp);
        }

        stack_destroy(stack);

        char destDirSave[1024] = {0};
        strcpy(destDirSave, realDir);
        strcat(destDirSave, "/");
        strcat(destDirSave, destDirTemp);

        strcpy(destDir, destDirSave);
        if(access(destDir, F_OK) != 0) {
            printf("cdDir路径不存在\n");
            returnValue =  -1;
        }
        else {
            printf("real destDir is %s\n", destDir);   
        }
    }

    // 用小火车协议发
    train_t train;
    train.length = strlen(destDirTemp);
    memcpy(train.data, destDirTemp, train.length);
    send(netfd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);

    printf("cd之后的路径为: %s\n\n", destDirTemp);

    if(returnValue == -1) {
        return -1;
    }
    return 1;
}

int lsDir(int netfd, const char *srcDir) {
    // 初始化传出参数
    char content[4096] = {0};

    // 对目录里文件进行挨个读取
    DIR *dirp = opendir(srcDir);
    struct dirent *pdirent;
    while((pdirent = readdir(dirp)) != NULL) {
        // 若为. ..则不打印
        if(strcmp(pdirent->d_name, ".") == 0 ||
           strcmp(pdirent->d_name, "..") == 0) {
            continue;
        }
        // 正常存入
        strcat(content, pdirent->d_name);
        // 若是文件夹, 显示时加个/
        if(pdirent->d_type == DT_DIR) {
            strcat(content, "/");
        }
        strcat(content, "  ");
    }

    closedir(dirp);

    // 把绝对路径转化为虚拟路径
    char realDir[1024] = {0};
    getcwd(realDir, sizeof(realDir));
    char diffDir[1024] = {0};
    getPathDiff(realDir, srcDir, diffDir);

    // 用小火车协议发  传char *destDir, char *content
    train_t train;
    train.length = strlen(diffDir);
    memcpy(train.data, diffDir, train.length);
    send(netfd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);

    train.length = strlen(content);
    memcpy(train.data, content, train.length);
    send(netfd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);

    printf("ls之后的路径为: %s\n", diffDir);
    printf("ls的内容为: %s\n\n", content);

    return 1;
}

int pwdDir(int netfd, const char *srcDir) {
    // 把绝对路径转化为虚拟路径
    char realDir[1024] = {0};
    getcwd(realDir, sizeof(realDir));
    char diffDir[1024] = {0};
    getPathDiff(realDir, srcDir, diffDir);

    // 用小火车协议发
    train_t train;
    train.length = strlen(diffDir);
    memcpy(train.data, diffDir, train.length);
    send(netfd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);

    printf("pwd之后的路径为: \n%s\n\n", diffDir);

    return 1;
}

int mkDir(int netfd, const char *srcDir, const char *newDir) {
    int returnValue = 1;

    // 拼接成完整地址
    char destDir[1024] = {0};
    strcat(destDir, srcDir);
    strcat(destDir, "/");
    strcat(destDir, newDir);
    
    // 创建文件夹, 不需要access检查
    int ret = mkdir(destDir, 0777);
    if(ret == -1) {
        printf("mkDir创建文件夹出错\n");
        returnValue = -1;
    }

    // 把绝对路径转化为虚拟路径
    char realDir[1024] = {0};
    getcwd(realDir, sizeof(realDir));
    char diffDir[1024] = {0};
    getPathDiff(realDir, srcDir, diffDir);
    
    // 返回原地址
    // 用小火车协议发
    train_t train;
    train.length = strlen(diffDir);
    memcpy(train.data, diffDir, train.length);
    send(netfd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);
    
    printf("mkdir之后的路径为: %s\n\n", diffDir);
    
    if(returnValue == -1) {
        return -1;
    }
    return 1;
}

int rmDir(int netfd, const char *srcDir, const char *delDir) {
    int returnValue = 1;

    // 拼接成完整地址
    char destDir[1024] = {0};
    strcat(destDir, srcDir);
    strcat(destDir, "/");
    strcat(destDir, delDir);

    // 删除文件夹, 需要access检查
    if(access(destDir, F_OK) != 0) {
        printf("rmDir文件夹不存在\n");
        returnValue = -1;
    }

    if(returnValue == 1) {
        int ret = rmdir(destDir);
        if(ret == -1) {
            printf("rmDir文件夹非空\n");
            returnValue = -1;
        }       
    }

    // 把绝对路径转化为虚拟路径
    char realDir[1024] = {0};
    getcwd(realDir, sizeof(realDir));
    char diffDir[1024] = {0};
    getPathDiff(realDir, srcDir, diffDir);

    // 用小火车协议发
    train_t train;
    train.length = strlen(diffDir);
    memcpy(train.data, diffDir, train.length);
    send(netfd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);

    printf("rmdir之后的路径为: %s\n\n", diffDir);

    if(returnValue == -1) {
        return -1;
    }
    return 1;
}

int rmFile(int netfd, const char *srcDir, const char *delFile) {
    int returnValue = 1;

    char file[1024] = {0};
	strcpy(file, delFile);
    
    char path[1024] = {0};
	strcpy(path, srcDir);

    strcat(path, "/");
    strcat(path, file);

    if(unlink(path) == 0) {
        printf("成功删除文件: %s\n\n", file);
    }
	else{
        printf("删除文件失败\n\n");
		returnValue = -1;
    }

    // 把绝对路径转化为虚拟路径
    char realDir[1024] = {0};
    getcwd(realDir, sizeof(realDir));
    char diffDir[1024] = {0};
    getPathDiff(realDir, srcDir, diffDir);

    // 用小火车协议发
    train_t train;
    train.length = strlen(diffDir);
    memcpy(train.data, diffDir, train.length);
    send(netfd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);

    if(returnValue == -1) {
        return -1;
    }
    return 1;
}


